// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SampleEquityPairStrategyModel.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge.Plugins
{
    #region Usings

    using System.Reflection;

    using Org.OpenTrader.Framework.Enums;
    using Org.OpenTrader.Framework.Forge.Enums;
    using Org.OpenTrader.Framework.Forge.Events;
    using Org.OpenTrader.Framework.Forge.Interfaces;
    using Org.OpenTrader.Framework.LiveObjects;
    using Org.OpenTrader.Framework.LiveObjects.Interfaces;

    #endregion

    /// <summary>
    /// The sample pair strategy plugin.
    /// </summary>
    [Credits("Sample Strategy Plugin", "Example to illustrate the use of models", "David Denis", 
        "Copyright (C) David Denis <mailto:david.denis@systemathics.com>")]
    [ImplementsInterface("Org.OpenTrader.Framework.Forge.Interfaces.IStrategyPlugin")]
    public sealed class SampleEquityPairStrategyModel : StrategyModel
    {
        #region Constants and Fields

        /// <summary>
        /// The identity.
        /// </summary>
        private static readonly Identity Identity = Identity.Create(MethodBase.GetCurrentMethod());

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SampleEquityPairStrategyModel"/> class.
        /// </summary>
        /// <param name="descriptor">
        /// The descriptor.
        /// </param>
        /// <param name="container">
        /// The container.
        /// </param>
        public SampleEquityPairStrategyModel(ILiveObjectDescriptor descriptor, ILiveObjectContainer container)
            : base(descriptor, container)
        {
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets Name.
        /// </summary>
        public override string Name
        {
            get
            {
                return "SampleEquityPairStrategyModel";
            }
        }

        /// <summary>
        /// Number of the Strategy Parameters
        /// </summary>
        public override int NbParams
        {
            get
            {
                return 14;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The on startup.
        /// </summary>
        /// <returns>
        /// </returns>
        public override Status Create()
        {
            if (this.SetCells())
            {
                this.Start();
            }

            return Status.Success(Identity);
        }

        /// <summary>
        /// The on shutdown.
        /// </summary>
        /// <returns>
        /// </returns>
        public override Status Destroy()
        {
            this.Stop();

            return Status.Success(Identity);
        }

        /// <summary>
        /// The on feed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        public override void OnFeed(object sender, FeedEventArgs args)
        {
        }

        /// <summary>
        /// The on order.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="args">
        /// The args.
        /// </param>
        public override void OnOrder(object sender, OrderTrackingEventArgs args)
        {
            Logging.Log(
                Identity, 
                ELogLevel.Debug, 
                () => string.Format("OnOrder : Traded Nominal Expo = {0}", this.Expo[EExpoCellType.Traded].NominalExpo));
        }

        /// <summary>
        /// The run.
        /// </summary>
        public override void Run()
        {
        }

        /// <summary>
        /// The set param.
        /// </summary>
        /// <param name="key">
        /// The key.
        /// </param>
        /// <param name="val">
        /// The val.
        /// </param>
        /// <returns>
        /// The set param.
        /// </returns>
        public override bool SetParam(string key, Table.Cell val)
        {
            return false;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Set the strategy cells
        /// </summary>
        /// <returns>
        /// The set cells.
        /// </returns>
        protected override bool SetCells()
        {
            // Check The Config
            if (this.CellsConfig == null)
            {
                Logging.Log(Identity, ELogLevel.Error, () => string.Format("SetCells : Invalid Strategy Cells Config"));
                return false;
            }

            // Check Nb Parameters
            if (this.CellsConfig.ColCount < this.NbParams)
            {
                Logging.Log(
                    Identity, 
                    ELogLevel.Error, 
                    () =>
                    string.Format(
                        "SetCells : Invalid Strategy Cells Config, Nb Parameters, Cols={0} / Params={1}", 
                        this.CellsConfig.ColCount, 
                        this.NbParams));
                return false;
            }

            // Check Params Name
            var iName = this.CellsConfig.ColumnIndex("Name");
            var iStartAt = this.CellsConfig.ColumnIndex("StartAt");
            var iStopAt = this.CellsConfig.ColumnIndex("StopAt");
            var iNominal = this.CellsConfig.ColumnIndex("Nominal");
            var iMaxCap = this.CellsConfig.ColumnIndex("MaxCap");
            var iNominalTrade = this.CellsConfig.ColumnIndex("NominalTrade");
            var iTradeDelay = this.CellsConfig.ColumnIndex("TradeDelay");
            var iModifyDelay = this.CellsConfig.ColumnIndex("ModifyDelay");
            var iMinDev = this.CellsConfig.ColumnIndex("MinDev");
            var iUniverse = this.CellsConfig.ColumnIndex("Universe");
            var iRdtFilter = this.CellsConfig.ColumnIndex("RdtFilter");
            var iCancelMarge = this.CellsConfig.ColumnIndex("CancelMarge");
            var iMinRealloc = this.CellsConfig.ColumnIndex("MinRealloc");
            var iStopLoss = this.CellsConfig.ColumnIndex("StopLoss");

            if (iName == -1 || iStartAt == -1 || iStopAt == -1 || iNominal == -1 || iMaxCap == -1 || iNominalTrade == -1 ||
                iNominalTrade == -1 || iTradeDelay == -1 || iModifyDelay == -1 || iMinDev == -1 || iUniverse == -1 ||
                iRdtFilter == -1 || iCancelMarge == -1 || iMinRealloc == -1 || iStopLoss == -1)
            {
                Logging.Log(
                    Identity, 
                    ELogLevel.Error, 
                    () =>
                    string.Format(
                        "SetCells : Invalid Strategy Cells Config, Header should be like : Name,StartAt,StopAt,Nominal,MaxCap,NominalTrade,TradeDelay,ModifyDelay,MinDev,Universe,RdtFilter,CancelMarge,MinRealloc,StopLoss"));
                return false;
            }

            // Check duplicated Names
            ////Table.Column colNames = this.CellsConfig[iName];

            // Set StrategyModelCells
            for (var i = 0; i < this.CellsConfig.RowCount; i++)
            {
                // Set StrategyModelCell
                IStrategyModelCell cell = new SampleEquityPairStrategyModelCell(this);
                string name = this.CellsConfig[i, iName];
                var insert = true;
                for (var j = 0; j < this.NbParams; j++)
                {
                    if (!cell.SetParam(this.CellsConfig.ColumnNames[j], this.CellsConfig[i, j]))
                    {
                        Logging.Log(
                            Identity, 
                            ELogLevel.Error, 
                            () => string.Format("SetCells : Cannot create StrategyModelCell {0}, invalid params", name));
                        insert = false;
                        j = this.NbParams;
                    }
                }

                // Add StrategyModelCell to the StrategyModel
                if (insert)
                {
                    this.Add(cell);
                }
            }

            return true;
        }

        #endregion

        /// <summary>
        /// The sample equity pair strategy model cell.
        /// </summary>
        public class SampleEquityPairStrategyModelCell : StrategyModelCell
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(MethodBase.GetCurrentMethod());

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="SampleEquityPairStrategyModelCell"/> class. 
            /// SampleEquityPairStrategyModelCell
            /// </summary>
            /// <param name="parent">
            /// </param>
            public SampleEquityPairStrategyModelCell(IStrategyModel parent)
                : base(parent)
            {
            }

            #endregion

            #region Properties

            /// <summary>
            /// Nb Parameters
            /// </summary>
            public override int NbParams
            {
                get
                {
                    return 5;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// OnFeed
            /// </summary>
            /// <param name="sender">
            /// </param>
            /// <param name="args">
            /// </param>
            public override void OnFeed(object sender, FeedEventArgs args)
            {
                // Logging.Log(Identity, ELogLevel.Debug, () => string.Format("OnFeed : received {0}", args.ToString()));
                if (args is FeedEventArgs.ConnectionStatus)
                {
                }
                else if (args is FeedEventArgs.MarketBookUpdate)
                {
                }
                else if (args is FeedEventArgs.MarketFieldUpdate)
                {
                }
            }

            /// <summary>
            /// OnOrder
            /// </summary>
            /// <param name="sender">
            /// </param>
            /// <param name="args">
            /// </param>
            public override void OnOrder(object sender, OrderTrackingEventArgs args)
            {
                Logging.Log(Identity, ELogLevel.Debug, () => string.Format("OnOrder : received {0}", args.ToString()));
            }

            /// <summary>
            /// Override SetParms
            /// </summary>
            /// <param name="key">
            /// </param>
            /// <param name="val">
            /// </param>
            /// <returns>
            /// The set param.
            /// </returns>
            public override bool SetParam(string key, Table.Cell val)
            {
                // Nominal
                if (key == "Nominal")
                {
                    return true;
                }

                // MaxCap
                if (key == "MaxCap")
                {
                    return true;
                }

                // NominalTrade
                if (key == "NominalTrade")
                {
                    return true;
                }

                // TradeDelay
                if (key == "TradeDelay")
                {
                    return true;
                }

                // ModifyDelay
                if (key == "ModifyDelay")
                {
                    return true;
                }

                // MinDev
                if (key == "MinDev")
                {
                    return true;
                }

                // Universe
                if (key == "Universe")
                {
                    if (this.Status == EStrategyStatus.Stopped)
                    {
                        this.Config = val;
                        return this.SetUniverse();
                    }
                    else
                    {
                        Logging.Log(
                            Identity, 
                            ELogLevel.Error, 
                            () =>
                            string.Format(
                                "SetParam : cannot set Universe, strategy not stopped : {0} - {1}", 
                                this.Name, 
                                ((StrategyPlugin)this.Parent).Name));
                        return false;
                    }
                }

                // RdtFilter
                if (key == "RdtFilter")
                {
                    return true;
                }

                // CancelMarge
                if (key == "CancelMarge")
                {
                    return true;
                }

                // MinRealloc
                if (key == "MinRealloc")
                {
                    return true;
                }

                // StopLoss
                if (key == "StopLoss")
                {
                    return true;
                }

                return base.SetParam(key, val);
            }

            #endregion

            #region Methods

            /// <summary>
            /// Set Universe
            /// </summary>
            /// <returns>
            /// The set universe.
            /// </returns>
            protected bool SetUniverse()
            {
                // Check The Config
                if (this.Config == null)
                {
                    Logging.Log(
                        Identity, ELogLevel.Error, () => string.Format("SetUniverse {0} : Invalid Config", this.Name));
                    return false;
                }

                // Check Nb Parameters
                if (this.Config.ColCount < this.NbParams)
                {
                    Logging.Log(
                        Identity, 
                        ELogLevel.Error, 
                        () =>
                        string.Format(
                            "SetCells {0} : Invalid Config, Nb Parameters, Cols={1} / Params={2}", 
                            this.Name, 
                            this.Config.ColCount, 
                            this.NbParams));
                    return false;
                }

                // Check Params Name
                var iBBCode = this.Config.ColumnIndex("BBCode");
                var iActive = this.Config.ColumnIndex("Active");
                var iBuy = this.Config.ColumnIndex("Buy");
                var iSell = this.Config.ColumnIndex("Sell");
                var iTR = this.Config.ColumnIndex("TR");

                if (iBBCode == -1 || iActive == -1 || iBuy == -1 || iBuy == -1 || iSell == -1 || iTR == -1)
                {
                    Logging.Log(
                        Identity, 
                        ELogLevel.Error, 
                        () =>
                        string.Format(
                            "SetCells {0} : Invalid Config, Header should be like : BBCode,Active,Buy,Sell,TR", 
                            this.Name));
                    return false;
                }

                // Check duplicated Names
                ////Table.Column colBBCodes = this.CellsConfig[iBBCode];

                // Set Instruments
                var ret = true;
                for (var i = 0; i < this.Config.RowCount; i++)
                {
                    ret = this.Add(this.Config[i, iBBCode]) ? ret : false;
                }

                return ret;
            }

            #endregion
        }
    }
}